package br.dcc.ufmg.filtering;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import br.dcc.ufmg.domain.Threshold;

import com.fathzer.soft.javaluator.AbstractEvaluator;
import com.fathzer.soft.javaluator.BracketPair;
import com.fathzer.soft.javaluator.Operator;
import com.fathzer.soft.javaluator.Parameters;

public class MeasuresEvaluator extends AbstractEvaluator<Boolean> {

	private Map<String, Float> measures = new LinkedHashMap<>();

	private static final Operator AND = new Operator("AND", 2,
			Operator.Associativity.LEFT, 2);

	public final static Operator OR = new Operator("OR", 2,
			Operator.Associativity.LEFT, 1);

	private static final Parameters PARAMETERS;

	static {
		PARAMETERS = new Parameters();
		PARAMETERS.add(AND);
		PARAMETERS.add(OR);
		PARAMETERS.addExpressionBracket(BracketPair.PARENTHESES);
	}

	public MeasuresEvaluator() {
		super(PARAMETERS);
	}

	@Override
	protected Boolean toValue(String arg0, Object arg1) {
		return getValue(arg0);
	}

	private boolean getValue(String literal) {
		boolean previousEvaluation = previousEvaluation(literal);
		String range = literal.substring(0, literal.indexOf("["));
		String metric = literal.substring(literal.indexOf("[") + 1,
				literal.indexOf("]"));
		Threshold t = Threshold.getByName(metric);
		boolean evaluation = evaluateMeasure(range, metric, t);
		return previousEvaluation || evaluation;
	}

	private boolean previousEvaluation(String literal) {
		if (literal.endsWith("=true"))
			return true;
		else if (literal.endsWith("=false"))
			return false;
		return false;
	}

	private boolean evaluateMeasure(String range, String metric, Threshold t) {
		boolean evaluation = false;
		switch (range) {
		case "UNCOMMON":
			evaluation = measures.get(metric.equals("NRM") ? "NORM" : metric) > t.getThresholdUncommon();
			break;
		case "COMMON":
			evaluation = measures.get(metric.equals("NRM") ? "NORM" : metric) <= t.getThresholdCommon();
			break;
		case "CASUAL":
			evaluation = measures.get(metric.equals("NRM") ? "NORM" : metric) > t.getThresholdCommon()
					&& measures.get(metric.equals("NRM") ? "NORM" : metric) <= t.getThresholdUncommon();
			break;
		default:
			evaluation = false;
			break;
		}
		return evaluation;
	}

	@Override
	protected Boolean evaluate(Operator operator, Iterator<Boolean> operands,
			Object evaluationContext) {
		Boolean o1 = operands.next();
		Boolean o2 = operands.next();
		Boolean result;
		if (operator == OR) {
			result = o1 || o2;
		} else if (operator == AND) {
			result = o1 && o2;
		} else {
			throw new IllegalArgumentException();
		}
		return result;
	}

	public void addMeasures(String metric, Float value) {
		measures.put(metric, value);
	}

}
